package edu.utn.tacs.gestion.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Set;

import org.apache.log4j.Logger;

import edu.utn.tacs.gestion.domain.impl.Comentario;
import edu.utn.tacs.gestion.domain.impl.Evento;
import edu.utn.tacs.gestion.domain.impl.Usuario;
import edu.utn.tacs.gestion.domain.impl.UsuarioAdministrador;
import edu.utn.tacs.gestion.exception.BusinessException;
import edu.utn.tacs.gestion.service.dao.impl.DaoFactory;
import edu.utn.tacs.gestion.service.dao.interfaces.IGestionEventosDao;
import edu.utn.tacs.gestion.service.interfaces.IGestionEventosService;

/**
 * Clase de servicio para desacoplar la comunicacion entre la capa de presententacion y las capas de negocio y de persistencia
 */
public class GestionEventosService implements IGestionEventosService {
	
	private static IGestionEventosService instance = null;
	IGestionEventosDao ged = DaoFactory.createGestionEventosDaoDummy();
	static Logger logger = Logger.getLogger(GestionEventosService.class);
	
	public static IGestionEventosService getInstance() {
      if(instance == null) {
         instance = new GestionEventosService();
      }
      return instance;
   }

	/**
	 * Registra un usuario nuevo en la red social
	 */
	public Usuario registrarUsuario(Long nroDocumento, String nombre) throws BusinessException {
		logger.debug("Metodo: registrarUsuario()");
		Usuario usuario = new Usuario(nroDocumento, nombre);
		return ged.storeUsuario(usuario);
	}
	
	public boolean existeUsuario(Usuario usuario) {
		logger.debug("Metodo: existeUsuario()");
		return ged.existeUsuario(usuario);
	}
	
	public boolean existeUsuarioAdministrador(UsuarioAdministrador usuarioAdministrador) {
		logger.debug("Metodo: existeUsuarioAdministrador()");
		return ged.existeUsuarioAdministrador(usuarioAdministrador);
	}
	
	public UsuarioAdministrador crearUsuarioAdministrador(Long nroDocumento, String nombre) throws BusinessException {
		logger.debug("Metodo: crearUsuarioAdministrador()");
		UsuarioAdministrador usuarioAdministrador = new UsuarioAdministrador(nroDocumento, nombre);
		return ged.storeUsuarioAdministrador(usuarioAdministrador);
	}
	

	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#getUsuario(java.lang.Long)
	 */
	public Usuario getUsuario(Long nroDocumento) throws BusinessException {
		logger.debug("Metodo: getUsuario()");
		return ged.getUsuario(nroDocumento);
	}
	
	public UsuarioAdministrador getUsuarioAdministrador(Long nroDocumento) throws BusinessException {
		logger.debug("Metodo: getUsuarioAdministrador()");
		return ged.getUsuarioAdministrador(nroDocumento);
	}
	
	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#getEvento(java.lang.String, java.lang.String)
	 */
	public Evento getEvento(String nombre, String fecha) throws BusinessException {
		logger.debug("Metodo: getEvento()");
		return ged.getEvento(nombre, fecha);
	}
	
	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#crearEvento(edu.utn.tacs.gestion.domain.impl.Usuario, java.lang.String, java.lang.String, java.util.Date, double, java.lang.String)
	 */
	public Evento crearEvento(Usuario usuario, String nombreEvento, String descripcionEvento, 
			Date fechaEvento, double duracionEvento, String ubicacionEvento) throws BusinessException {
		logger.debug("Metodo: crearEvento()");
		Evento evento = usuario.crearEvento(nombreEvento, descripcionEvento, fechaEvento,
				duracionEvento, ubicacionEvento);
		//ged.storeUsuario(usuario);
		logger.debug("Pesistiendo evento");
		logger.info("Evento creado: " + evento.getNombre());
		return evento;
	}
	
	public boolean existeEvento(Evento evento) {
		logger.debug("Metodo: existeEvento()");
		return ged.existeEvento(evento);
	}
	
	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#suscribirAEvento(edu.utn.tacs.gestion.domain.impl.Usuario, edu.utn.tacs.gestion.domain.impl.Evento)
	 */
	public void suscribirAEvento(Usuario usuario, Evento evento) throws BusinessException {
		logger.debug("Metodo: suscribirAEvento()");
		evento.suscribirAEvento(usuario);
		//ged.storeUsuario(usuario);
	}
	
	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#isUsuarioRegistrado(edu.utn.tacs.gestion.domain.impl.Evento, edu.utn.tacs.gestion.domain.impl.Usuario)
	 */
	public boolean isUsuarioRegistrado(Evento evento, Usuario usuario) {
		logger.debug("Metodo: isUsuarioRegistrado()");
		return evento.isUsuarioRegistrado(usuario);
	}
	
	/* (non-Javadoc)
	 * @see edu.utn.tacs.gestion.service.IGestionEventosService#cancelarSuscripcionAEvento(edu.utn.tacs.gestion.domain.impl.Usuario, edu.utn.tacs.gestion.domain.impl.Evento)
	 */
	public void cancelarSuscripcionAEvento(Usuario usuario, Evento evento) throws BusinessException {
		logger.debug("Metodo: cancelarSuscripcionAEvento()");
        evento.cancelarSuscripcionAEvento(usuario);		
	}
	
	/**
	 * Permite consultar todas las suscripciones realizadas por un usuario
	 * @param usuario
	 * @return
	 */
	public Collection<Evento> consultarSuscripcionesUsuario(Usuario usuario) {
		logger.debug("Metodo: consultarSuscripcionesUsuario()");
		Collection<Evento> eventosUsuario = new ArrayList<Evento>(); 
		Collection<Evento> eventos = DaoFactory.createGestionEventosDaoDummy().getEventos();
		for(Evento evento: eventos) {
			if(evento.getUsuariosRegistrados().contains(usuario)) eventosUsuario.add(evento);
		}
		return eventosUsuario;
	}
	
	/**
	 * Permite consultar todos los usuarios registrados a un evento
	 * @param evento
	 * @return usuariosRegistrados
	 */
	public Collection<Usuario> consultarSuscripcionesEvento(Evento evento) {
		logger.debug("Metodo: getUsuariosRegistrados()");
		return evento.getUsuariosRegistrados();
	}
	
	/**
	 * Permite registrar la asistencia de un usuario a un evento
	 * @param usuario
	 */
	public void registrarAsistencia(Evento evento, Usuario usuario) throws BusinessException {
		logger.debug("Metodo: registrarAsistencia()");
		Set<Usuario> usuariosRegistados = evento.getUsuariosRegistrados();
		Set<Usuario> usuariosAsistentes = evento.getUsuariosAsistentes();
		if(usuariosRegistados.contains(usuario)) {
			if (!(usuariosAsistentes.contains(usuario))) {
				evento.registrarAsistencia(usuario);
				//ged.storeUsuario(usuario);
			} else {
				logger.error("BusinessException: No se puede registrar la asistencia de un usuario que no esta registrado");
				throw new BusinessException("No se puede registrar la asistencia de un usuario que no esta registrado");
			}
		} else {
			logger.error("BusinessException: El usuario no se encuentra registrado en el evento");
			throw new BusinessException("El usuario no se encuentra registrado en el evento");
		}
	}
	
	public boolean asistioUsuario(Evento evento, Usuario usuario) {
		logger.debug("Metodo: asistioUsuario()");
		Set<Usuario> usuariosAsistentes = evento.getUsuariosAsistentes();
		for(Usuario usr: usuariosAsistentes) {
			if(usr.equals(usuario)) {
				logger.info("El Usuario: " + usuario.getNombre() + " asistio al Evento: " + evento.getNombre());
				return true;
			}
		}
		logger.warn("El Usuario: " + usuario.getNombre() + " NO asistio al Evento: " + evento.getNombre());
		return false;
	}
	
	public Comentario agregarComentario(Evento evento, Usuario usuario, String descripcion) throws BusinessException {
		logger.debug("Metodo: agregarComentario()");
		if(evento.getUsuariosAsistentes().contains(usuario)) {
			Comentario comentario = evento.agregarComentario(usuario, descripcion);
			//ged.storeUsuario(usuario);
			return comentario;
		} else {
			logger.error("BusinessException: No es posible registrar un comentario de un usuario que no asistio al evento");
			throw new BusinessException("No es posible registrar un comentario de un usuario que no asistio al evento");
		}
	}
	
	
}
